#include <string>
#include <vector>
#include <iostream>

// 使用位运算来表示左右括号
void solve_bracket(std::vector<std::string>&res,int n)
{   
    // 总共有2n个括号
    int total = 1<< (2*n);          // 2的2n次方
    // 枚举所有的可能性,巧妙之处在于使用位运算来表示括号的两种状态
    for (int i=0;i<total;i++)      // 其实无需全部枚举到total-1，因为不合法的括号序列会被提前跳出
    {
        int left = 0;
        int right = 0;
        std::string s;
        for (int j=0;j<2*n;j++)
        {
            // 判断第j位是0还是1
            if (i & (1<<j))
            {
                s.push_back('(');
                left++;
            }
            else
            {
                s.push_back(')');
                right++;
            }
            // 如果右括号多于左括号，说明不合法，直接跳出
            if (right>left)        // 如果左大于 n/2 也可以跳出
            {
                break;
            }
        }
        // 如果左右括号数量相等，说明是合法的括号序列
        if (left==right)
        {
            res.push_back(s);
        }
    }
}

// 总结:
// 1. 使用位运算来表示括号的两种状态，0表示右括号，1表示左括号
// 2. 通过枚举范围内的所有数字，来生成所有可能的括号序列
// 3. 在生成过程中，实时统计左右括号的数量，如果右括号多于左括号，说明不合法，直接跳出
// 4. 最后判断左右括号数量是否相等，如果相等则说明是合法的括号序列，加入结果集

void solve_bracket1(void)
{
    // 这就像养牛的大姐被牛从中间拦腰顶断
    // 六层楼宿舍电梯可以到15楼上面每天都在死人
    // 声控设备把主人和客人全部砍死
    // 使用递归就像你坐电梯从15楼到6楼 ???????????????   
}

int main()
{
    int n = 0;
    std::cin>>n;
    std::vector<std::string>v;
    solve_bracket(v,n);

    for (auto s:v)
    {
        std::cout<<s<<std::endl;
    }
    return 0;
}